package com.svms.service.dml.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.svms.domain.dao.SvmsVehicleMapper;
import com.svms.model.SvmsVehicle;
import com.svms.model.SvmsVehicleExample;
import com.svms.model.SvmsVehicleExample.Criteria;
import com.svms.service.constants.Constants;
import com.svms.service.constants.SvmsStatusCodes;
import com.svms.service.dml.iface.VehicleDMLIF;
import com.svms.service.factory.SvmsServiceFactory;
import com.svms.service.mapper.VehicleMapper;
import com.svms.service.search.SearchFilter;
import com.svms.service.search.SearchOperators;
import com.svms.service.util.NumberGeneratorUtils;
import com.svms.service.validators.VehicleValidator;
import com.svms.service.vo.ResultCodeVO;
import com.svms.service.vo.VehicleVO;

public class VehicleDML implements VehicleDMLIF {

	private static Logger logger = Logger.getLogger(VehicleDML.class);

	@Autowired
	private SvmsVehicleMapper svmsVehicleMapper;

	/**
	 * Completed
	 */
	@Override
	public VehicleVO insertNewVehicle(VehicleVO vehicle) {
		logger.debug("inside AddVehicle insertNewVehicle method");
		ResultCodeVO resultCode = new ResultCodeVO();
		try {
			vehicle.setVehicleId(String.valueOf(NumberGeneratorUtils
					.generateVehicleId()));
			int successCode = svmsVehicleMapper.insert(VehicleMapper
					.serviceToDml(vehicle));
			if (successCode != 1) {
				resultCode
						.addErrorDetail(SvmsStatusCodes.INSERTING_VEHICLE_INTO_DATABASE_FAILED);
				vehicle.setResultCode(resultCode);
			}
			logger.debug("exiting from insertNewVehicle method");
		} catch (Exception e) {
			logger.error("Error occured in insertNewVehicle method");
			e.printStackTrace();
			resultCode.addErrorDetail(SvmsStatusCodes.DAO_EXCEPTION);
			vehicle.setResultCode(resultCode);
		}

		return vehicle;

	}

	/**
	 * Completed
	 */
	@Override
	public VehicleVO editVehicle(VehicleVO vehicle) {
		logger.debug("inside  editVehicle method");
		SvmsVehicle svmsVehicle = new SvmsVehicle();
		ResultCodeVO resultCode = new ResultCodeVO();
		Date date;
		boolean isUpdate = false;
		try {
			SvmsVehicleExample svmsVehicleExample = new SvmsVehicleExample();
			Criteria criteria = svmsVehicleExample.createCriteria();
			criteria.andVehicleIdEqualTo(Long.parseLong(vehicle.getVehicleId()));
			svmsVehicle.setVehicleId(Long.parseLong(vehicle.getVehicleId()));

			VehicleVO vehicleFromDb = SvmsServiceFactory.getInstance()
					.getVehicle().getVehicle(vehicle);

			// This if condition makes sure that there is only one data returned
			// from DB
			if (vehicleFromDb != null
					&& vehicleFromDb.getResultCode() != null
					&& vehicleFromDb.getResultCode().getErrorDetails().size() == 0) {
				SvmsVehicle data = VehicleMapper.serviceToDml(vehicleFromDb);
				if (!data.getForm47().equals(
						vehicle.getVehicleDocuments().get("FORM47_TD"))) {
					date = vehicle.getVehicleDocuments().get("FORM47_TD");
					criteria.andForm47EqualTo(date);
					svmsVehicle.setForm47(date);
					isUpdate = true;
				}
				if (!data.getNc().equals(
						vehicle.getVehicleDocuments().get("NC_TD"))) {
					date = vehicle.getVehicleDocuments().get("NC_TD");
					criteria.andNcEqualTo(date);
					svmsVehicle.setNc(date);
					isUpdate = true;
				}
				if (!data.getFc().equals(
						vehicle.getVehicleDocuments().get("FC_TD"))) {
					date = vehicle.getVehicleDocuments().get("FC_TD");
					criteria.andFcEqualTo(date);
					svmsVehicle.setFc(date);
					isUpdate = true;
				}
				if (!data.getInsureance().equals(
						vehicle.getVehicleDocuments().get("INSURANCE_TD"))) {
					date = vehicle.getVehicleDocuments().get("INSURANCE_TD");
					criteria.andInsureanceEqualTo(date);
					svmsVehicle.setInsureance(date);
					isUpdate = true;
				}
				if (!data.getTax().equals(
						vehicle.getVehicleDocuments().get("TAX_TD"))) {
					date = vehicle.getVehicleDocuments().get("TAX_TD");
					criteria.andTaxEqualTo(date);
					svmsVehicle.setTax(date);
					isUpdate = true;
				}
				if (!data.getModel()
						.equalsIgnoreCase(vehicle.getModel().trim())) {
					String str = vehicle.getModel().trim();
					criteria.andModelEqualTo(str);
					svmsVehicle.setModel(str);
					isUpdate = true;
				}
				if (!data.getTotalDistance().equals(
						Integer.parseInt(vehicle.getDistanceTraveled().trim()))) {
					String str = vehicle.getDistanceTraveled().trim();
					criteria.andTotalDistanceEqualTo(Integer.parseInt(str));
					svmsVehicle.setTotalDistance(Integer.parseInt(str));
					isUpdate = true;
				}
				if (!data.getTransportId().equals(
						Long.parseLong(vehicle.getTransport().getTransportId()
								.trim()))) {
					String str = vehicle.getTransport().getTransportId().trim();
					criteria.andTransportIdEqualTo(Long.parseLong(str));
					svmsVehicle.setTransportId(Long.parseLong(str));
					isUpdate = true;
				}
				if (!data.getVehicleNo().equalsIgnoreCase(
						vehicle.getVehicleNumber().trim())) {
					String str = vehicle.getVehicleNumber().trim();
					criteria.andVehicleNoEqualTo(str);
					svmsVehicle.setVehicleNo(str);
					isUpdate = true;
				}
				criteria.andUpdatedTimeEqualTo(data.getUpdatedTime());
			} else {
				vehicle.setResultCode(vehicleFromDb.getResultCode());
				return vehicle;
			}

			if (isUpdate) {
				int successCode = svmsVehicleMapper
						.updateByPrimaryKeySelective(svmsVehicle);
				if (successCode != 1) {
					resultCode
							.addErrorDetail(SvmsStatusCodes.UPDATING_VEHICLE_INTO_DATABASE_FAILED);
					vehicle.setResultCode(resultCode);
				}
			} else {
				logger.info("No Updated Occured");
				resultCode.addErrorDetail(SvmsStatusCodes.NO_FIELDS_TO_UPDATE);
				vehicle.setResultCode(resultCode);
			}
			logger.debug("exiting from editVehicle method");
		} catch (Exception e) {
			logger.error("Error occured in editVehicle method");
			resultCode.addErrorDetail(SvmsStatusCodes.DAO_EXCEPTION);
			vehicle.setResultCode(resultCode);
		}
		return vehicle;
	}

	/**
	 * Completed
	 */
	@Override
	public VehicleVO deleteVehicle(VehicleVO vehicle) {
		logger.debug("inside deleteVehicle method");
		ResultCodeVO resultSet = new ResultCodeVO();
		try {
			int successCode = svmsVehicleMapper.deleteByPrimaryKey(Long
					.parseLong(vehicle.getVehicleId()));
			if (successCode != 1) {
				resultSet
						.addErrorDetail(SvmsStatusCodes.DELETING_VEHICLE_FROM_DATABASE_FAILED);
				vehicle.setResultCode(resultSet);
			}
			logger.debug("exiting from deleteVehicle method");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("Error occured in deleteVehicle method");
			resultSet.addErrorDetail(SvmsStatusCodes.DAO_EXCEPTION);
			vehicle.setResultCode(resultSet);
		}
		return vehicle;
	}

	@Override
	public VehicleVO getVehicle(VehicleVO vehicle) {
		logger.debug("inside getVehicle method");

		SvmsVehicle svmsVehicle = null;
		ResultCodeVO resultSet = new ResultCodeVO();

		try {
			SvmsVehicleExample svmsVehicleExample = new SvmsVehicleExample();
			Criteria criteria = svmsVehicleExample.createCriteria();

			if (StringUtils.isNotBlank(vehicle.getVehicleId())) {
				criteria.andVehicleIdEqualTo(Long.parseLong(vehicle
						.getVehicleId()));
			}
			if (StringUtils.isNotBlank(vehicle.getVehicleNumber())) {
				criteria.andVehicleNoEqualTo(vehicle.getVehicleNumber());
			}

			List<SvmsVehicle> vehicleList = svmsVehicleMapper
					.selectByExample(svmsVehicleExample);

			if (vehicleList != null) {
				if (vehicleList.size() == 1) {
					svmsVehicle = vehicleList.get(0);
					vehicle = VehicleMapper.dmlToService(svmsVehicle);
					vehicle.setResultCode(resultSet);
				} else if (vehicleList.size() > 1) {
					resultSet
							.addErrorDetail(SvmsStatusCodes.NO_UNIQUE_VEHILCE_FOUND);
					vehicle.setResultCode(resultSet);
				} else {
					resultSet.addErrorDetail(SvmsStatusCodes.NO_VEHILCE_FOUND);
					vehicle.setResultCode(resultSet);
				}
			} else {
				resultSet.addErrorDetail(SvmsStatusCodes.NO_VEHILCE_FOUND);
				vehicle.setResultCode(resultSet);
			}
			logger.debug("exiting from getVehicle method");
		} catch (Exception e) {
			logger.error("Error occured in getVehicle method");
			resultSet.addErrorDetail(SvmsStatusCodes.DAO_EXCEPTION);
			vehicle.setResultCode(resultSet);
		}
		return vehicle;
	}

	@Override
	public List<VehicleVO> getVehicleList() {
		logger.debug("inside getVehicleList method");
		List<SvmsVehicle> vehiclesList = null;
		List<VehicleVO> vehicles = new ArrayList<VehicleVO>();
		try {
			vehiclesList = svmsVehicleMapper.getEntireTableData();
			if (vehiclesList != null) {
				for (SvmsVehicle svmsVehicle : vehiclesList) {
					vehicles.add(VehicleMapper.dmlToService(svmsVehicle));
				}
			}
			logger.debug("exiting from getVehicleList method");
		} catch (Exception e) {
			logger.error("Error occured in getVehicleList method");
			e.printStackTrace();
		}
		return vehicles;
	}

	@Override
	public List<VehicleVO> searchVehicle(VehicleVO vehicle,
			Map<String, SearchOperators> searchOperators) {
		logger.debug("inside searchVehicle method");

		// ResultCodeVO resultSet = new ResultCodeVO();
		List<VehicleVO> vehicles = new ArrayList<VehicleVO>();

		try {
			SvmsVehicleExample svmsVehicleExample = new SvmsVehicleExample();

			createCriteriaForSearch(vehicle, searchOperators,
					svmsVehicleExample);

			// Additional critera will go here

			List<SvmsVehicle> vehicleList = svmsVehicleMapper
					.selectByExample(svmsVehicleExample);

			if (vehicleList != null) {
				for (SvmsVehicle svmsVehicle : vehicleList) {
					vehicles.add(VehicleMapper.dmlToService(svmsVehicle));
				}
			} else {
				/*
				 * resultSet.addErrorDetail(SvmsStatusCodes.NO_VEHILCE_FOUND);
				 * vehicle.setResultCode(resultSet); vehicles.add(vehicle);
				 */
			}

			logger.debug("exiting from searchVehicle method");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("Error occured in searchVehicle method");
			/*
			 * resultSet.addErrorDetail(SvmsStatusCodes.DAO_EXCEPTION);
			 * vehicle.setResultCode(resultSet); vehicles.add(vehicle);
			 */
		}
		return vehicles;
	}

	/**
	 * To create criteria for search vehicle field
	 * 
	 * @param vehicle
	 * @param searchOperators
	 * @param svmsVehicleExample
	 */
	private void createCriteriaForSearch(VehicleVO vehicle,
			Map<String, SearchOperators> searchOperators,
			SvmsVehicleExample svmsVehicleExample) {

		Criteria criteria = svmsVehicleExample.createCriteria();

		if (vehicle != null) {
			if (StringUtils.isNotBlank(vehicle.getVehicleId())) {
				criteria.andVehicleIdEqualTo(Long.parseLong(vehicle
						.getVehicleId()));
			}
			if (StringUtils.isNotBlank(vehicle.getVehicleNumber())) {
				criteria.andVehicleNoEqualTo(vehicle.getVehicleNumber());
			}

			if (StringUtils.isNotBlank(vehicle.getModel())) {
				criteria.andModelLike(vehicle.getModel());
			}

			if (vehicle.getTransport() != null) {
				if (StringUtils.isNotBlank(vehicle.getTransport()
						.getTransportId())) {
					criteria.andTransportIdEqualTo(Long.valueOf(vehicle
							.getTransport().getTransportId()));
				}
			}

			if (vehicle.getVehicleDocuments() != null) {
				Map<String, Date> vehicleDocs = vehicle.getVehicleDocuments();
				// Search Criteria / search filter for dates
				if (null != vehicleDocs.get(Constants.FORM47_TD)) {
					if (searchOperators.get(Constants.FORM47_TD_OPERATOR) != null) {
						SearchOperators searchOperator = searchOperators
								.get(Constants.FORM47_TD_OPERATOR);
						switch (searchOperator.getSearchOperatorId()) {
						case 1:
							criteria.andForm47EqualTo(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						case 2:
							criteria.andForm47NotEqualTo(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						case 3:
							criteria.andForm47LessThan(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						case 4:
							criteria.andForm47GreaterThan(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						case 5:
							criteria.andForm47LessThanOrEqualTo(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						case 6:
							criteria.andForm47GreaterThanOrEqualTo(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						default:
							criteria.andForm47EqualTo(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						}
					} else {
						criteria.andForm47EqualTo(vehicleDocs
								.get(Constants.FORM47_TD));

					}
				}

				if (null != vehicleDocs.get(Constants.FC_TD)) {
					if (searchOperators.get(Constants.FC_TD_OPERATOR) != null) {
						SearchOperators searchOperator = searchOperators
								.get(Constants.FC_TD_OPERATOR);
						switch (searchOperator.getSearchOperatorId()) {
						case 1:
							criteria.andFcEqualTo(vehicleDocs
									.get(Constants.FC_TD));
							break;
						case 2:
							criteria.andFcNotEqualTo(vehicleDocs
									.get(Constants.FC_TD));
							break;
						case 3:
							criteria.andFcLessThan(vehicleDocs
									.get(Constants.FC_TD));
							break;
						case 4:
							criteria.andFcGreaterThan(vehicleDocs
									.get(Constants.FC_TD));
							break;
						case 5:
							criteria.andFcLessThanOrEqualTo(vehicleDocs
									.get(Constants.FC_TD));
							break;
						case 6:
							criteria.andFcGreaterThanOrEqualTo(vehicleDocs
									.get(Constants.FC_TD));
							break;
						default:
							criteria.andFcEqualTo(vehicleDocs
									.get(Constants.FC_TD));
							break;
						}
					} else {
						criteria.andFcEqualTo(vehicleDocs.get(Constants.FC_TD));

					}
				}

				if (null != vehicleDocs.get(Constants.NC_TD)) {
					if (searchOperators.get(Constants.NC_TD_OPERATOR) != null) {
						SearchOperators searchOperator = searchOperators
								.get(Constants.NC_TD_OPERATOR);
						switch (searchOperator.getSearchOperatorId()) {
						case 1:
							criteria.andNcEqualTo(vehicleDocs
									.get(Constants.NC_TD));
							break;
						case 2:
							criteria.andNcNotEqualTo(vehicleDocs
									.get(Constants.NC_TD));
							break;
						case 3:
							criteria.andNcLessThan(vehicleDocs
									.get(Constants.NC_TD));
							break;
						case 4:
							criteria.andNcGreaterThan(vehicleDocs
									.get(Constants.NC_TD));
							break;
						case 5:
							criteria.andNcLessThanOrEqualTo(vehicleDocs
									.get(Constants.NC_TD));
							break;
						case 6:
							criteria.andNcGreaterThanOrEqualTo(vehicleDocs
									.get(Constants.NC_TD));
							break;
						default:
							criteria.andNcEqualTo(vehicleDocs
									.get(Constants.NC_TD));
							break;
						}
					} else {
						criteria.andNcEqualTo(vehicleDocs.get(Constants.NC_TD));

					}
				}

				if (null != vehicleDocs.get(Constants.INSURANCE_TD)) {
					if (searchOperators.get(Constants.INSURANCE_TD_OPERATOR) != null) {
						SearchOperators searchOperator = searchOperators
								.get(Constants.INSURANCE_TD_OPERATOR);
						switch (searchOperator.getSearchOperatorId()) {
						case 1:
							criteria.andInsureanceEqualTo(vehicleDocs
									.get(Constants.FORM47_TD));
							break;
						case 2:
							criteria.andInsureanceNotEqualTo(vehicleDocs
									.get(Constants.INSURANCE_TD));
							break;
						case 3:
							criteria.andInsureanceLessThan(vehicleDocs
									.get(Constants.INSURANCE_TD));
							break;
						case 4:
							criteria.andInsureanceGreaterThan(vehicleDocs
									.get(Constants.INSURANCE_TD));
							break;
						case 5:
							criteria.andInsureanceLessThanOrEqualTo(vehicleDocs
									.get(Constants.INSURANCE_TD));
							break;
						case 6:
							criteria.andInsureanceGreaterThanOrEqualTo(vehicleDocs
									.get(Constants.INSURANCE_TD));
							break;
						default:
							criteria.andInsureanceEqualTo(vehicleDocs
									.get(Constants.INSURANCE_TD));
							break;
						}
					} else {
						criteria.andInsureanceEqualTo(vehicleDocs
								.get(Constants.FORM47_TD));

					}
				}

				if (null != vehicleDocs.get(Constants.TAX_TD)) {
					if (searchOperators.get(Constants.TAX_TD_OPERATOR) != null) {
						SearchOperators searchOperator = searchOperators
								.get(Constants.TAX_TD_OPERATOR);
						switch (searchOperator.getSearchOperatorId()) {
						case 1:
							criteria.andTaxEqualTo(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						case 2:
							criteria.andTaxNotEqualTo(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						case 3:
							criteria.andTaxLessThan(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						case 4:
							criteria.andTaxGreaterThan(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						case 5:
							criteria.andTaxLessThanOrEqualTo(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						case 6:
							criteria.andTaxGreaterThanOrEqualTo(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						default:
							criteria.andTaxEqualTo(vehicleDocs
									.get(Constants.TAX_TD));
							break;
						}
					} else {
						criteria.andTaxEqualTo(vehicleDocs
								.get(Constants.TAX_TD));

					}
				}

			}
		}
	}
}
